package com.swt.testdemo.service.impl;


import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.swt.testdemo.config.ResponseMessage;
import com.swt.testdemo.dao.SysCaptchaDao;
import com.swt.testdemo.dao.SysUserDao;
import com.swt.testdemo.entity.SysCaptchaEntity;
import com.swt.testdemo.form.SysLoginForm;
import com.swt.testdemo.service.SysLoginService;
import com.swt.testdemo.shiro.ShiroUtils;
import com.swt.testdemo.shiro.UsernamePasswordMacToken;
import com.swt.testdemo.util.RedisUtil;
import com.swt.testdemo.util.ValidatorUtil;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

/**
 * @author BleethNie
 * @version 1.0
 * @date 2020-01-08 17:48
 **/
@Service("SysLoginService")
public class SysLoginServiceImpl implements SysLoginService {

    private static DateTime LAST_DELETE_CAPTION_TIME;

   // @Value(value = "${swt.login.mac}")
    private boolean swtLoginMac;

    @Autowired
    private SysUserDao sysUserDao;

    @Autowired
    private SysCaptchaDao sysCaptchaDao;

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public ResponseMessage login(SysLoginForm form) {
        HttpStatus httpStatus = HttpStatus.OK;

        //参数校验
        ValidatorUtil.validateEntity(form);

        //验证码校验
        String uuid = form.getUuid();
        String captcha = form.getCaptcha();
        String username = form.getUsername();
        String mac = form.getMac();
        SysCaptchaEntity sysCaptchaEntity = sysCaptchaDao.queryEntityByUuid(uuid);

        if (sysCaptchaEntity == null) {
            httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
            return new ResponseMessage(httpStatus.value(), "验证码校验失败");
        }

        String sysCaptcha = sysCaptchaEntity.getCaptcha();
        sysCaptchaDao.useEntity(uuid);
        if (StrUtil.isEmpty(sysCaptcha) || !StrUtil.equalsIgnoreCase(sysCaptcha, captcha)) {
            httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
            return new ResponseMessage(httpStatus.value(), "验证码校验失败");
        }

        String message = "登陆成功";
        Subject subject = ShiroUtils.getSubject();
        try {
            UsernamePasswordToken token = null;
            if (swtLoginMac) {
                token = new UsernamePasswordMacToken(username, form.getPassword(), mac);
            } else {
                token = new UsernamePasswordToken(username, form.getPassword());
            }
            subject.login(token);
            sysUserDao.updateUserLoginFail("1", username, 0);
        } catch (UnknownAccountException e) {
            httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
            message = e.getMessage();
        } catch (IncorrectCredentialsException e) {
            httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
            Integer failCount = sysUserDao.selectUserLoginFail(username);
            if (failCount == null) {
            } else if (failCount >= 2) {
                message = "账号已被锁定,请联系管理员";
                sysUserDao.updateUserLoginFail("0", username, 0);
            } else {
                failCount++;
                message = "密码错误,剩余重试次数" + (3 - failCount) + "次";
                sysUserDao.updateUserLoginFail("1", username, failCount);
            }
        } catch (LockedAccountException e) {
            httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
            message = e.getMessage();
        } catch (AccountException e) {
            httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
            message = e.getMessage();
        } catch (AuthenticationException e) {
            httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
            message = e.getMessage();
        }
        return new ResponseMessage(httpStatus.value(), message);
    }

    @Override
    public ResponseMessage logout() {
        ShiroUtils.logout();
        return new ResponseMessage(HttpStatus.OK.value(), "注销成功");
    }


    @Override
    public byte[] captcha(String uuid) {
        //每天删除一次captcha表记录
        DateTime current = DateUtil.date();
        DateTime before30Day = current.offset(DateField.DAY_OF_MONTH, -30);
        DateTime before1Day = current.offset(DateField.DAY_OF_MONTH, -1);
        DateTime expireDay = current.offset(DateField.MINUTE, 5);
        if (LAST_DELETE_CAPTION_TIME == null) {
            LAST_DELETE_CAPTION_TIME = current;
            sysCaptchaDao.deleteHistoryCaptcha(before30Day.toString());
        }
        if (LAST_DELETE_CAPTION_TIME.isBefore(before1Day)) {
            LAST_DELETE_CAPTION_TIME = current;
            sysCaptchaDao.deleteHistoryCaptcha(before30Day.toString());
        }
        //生成captcha
        LineCaptcha captcha = CaptchaUtil.createLineCaptcha(150, 50);
        String code = captcha.getCode();

        SysCaptchaEntity sysCaptchaEntity = new SysCaptchaEntity();
        sysCaptchaEntity.setCaptcha(code);
        sysCaptchaEntity.setUuid(uuid);
        sysCaptchaEntity.setCreatedTime(current);
        sysCaptchaEntity.setExpireTime(expireDay);
        sysCaptchaEntity.setStatus(SysCaptchaEntity.STATUS_VALID);
        sysCaptchaDao.insert(sysCaptchaEntity);
        return captcha.getImageBytes();
    }

    @Override
    public ResponseMessage crackUUid(String uuid) {
        SysCaptchaEntity sysCaptchaEntity = new SysCaptchaEntity();
        sysCaptchaEntity.setUuid(uuid);
        sysCaptchaEntity.setStatus(SysCaptchaEntity.STATUS_VALID);
        QueryWrapper<SysCaptchaEntity> wq = new QueryWrapper<>();
        wq.eq("uuid", uuid);
        sysCaptchaDao.update(sysCaptchaEntity,wq);
        return new ResponseMessage(HttpStatus.OK.value(), "破解成功");
    }
}
